package com.fred.colorpicker

import android.content.Context
import android.graphics.*
import android.os.Build
import android.util.AttributeSet
import android.util.Log
import android.view.View
import androidx.annotation.RequiresApi
import kotlin.math.max
import kotlin.math.min

class ColorWheelPalette: View {

    private val colors = intArrayOf(
        Color.RED,
        Color.YELLOW,
        Color.GREEN,
        Color.CYAN,
        Color.BLUE,
        Color.MAGENTA,
        Color.RED
    )

    private val borderSize by lazy {
        context.dip(3F)
    }
    //Hue, Saturation, Value
    private val huePaint: Paint by lazy {
        Paint(Paint.ANTI_ALIAS_FLAG)
    }
    private val saturationPaint: Paint by lazy {
        Paint(Paint.ANTI_ALIAS_FLAG)
    }
    private val borderPain by lazy {
        Paint(Paint.ANTI_ALIAS_FLAG).apply {
            color = Color.rgb(231, 231, 231)
        }
    }

    private val currentPoint by lazy {
        PointF()
    }

    constructor(context: Context?) : super(context){
        init()
    }
    constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs){
        init()
    }
    constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super(
        context,
        attrs,
        defStyleAttr
    ){
        init()
    }

    @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
    constructor(
        context: Context?,
        attrs: AttributeSet?,
        defStyleAttr: Int,
        defStyleRes: Int
    ) : super(context, attrs, defStyleAttr, defStyleRes){
        init()
    }

    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec)
        val specWidth = MeasureSpec.getSize(widthMeasureSpec)
        val specHeight = MeasureSpec.getSize(heightMeasureSpec)
        if (specWidth > specHeight) {
            setMeasuredDimension(heightMeasureSpec,heightMeasureSpec)
        }else{
            setMeasuredDimension(widthMeasureSpec,widthMeasureSpec)
        }
    }

    override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
        super.onSizeChanged(w, h, oldw, oldh)
        val width = w - paddingLeft - paddingRight - 2*borderSize
        val height = h - paddingTop - paddingBottom - 2*borderSize
        val hueShader = LinearGradient(0F, height, width, height, colors, null, Shader.TileMode.REPEAT)
        huePaint.shader = hueShader
        val start = borderSize+paddingLeft
        val saturationShader = LinearGradient(width, start, width, height + start,
            intArrayOf(Color.WHITE, Color.argb(0, 255, 255, 255), Color.BLACK),
            null,
            Shader.TileMode.REPEAT
        )
        saturationPaint.shader = saturationShader
    }

    override fun onDraw(canvas: Canvas?) {
        super.onDraw(canvas)
        val dWidth = width - paddingLeft - paddingRight - 2*borderSize
        val dHeight = height - paddingTop - paddingBottom - 2*borderSize
        canvas?.drawRect(
            paddingLeft.toFloat(), paddingTop.toFloat(),
            dWidth + 2 * borderSize + paddingLeft, dHeight + 2 * borderSize + paddingTop, borderPain
        )
        val start = borderSize+paddingLeft
        canvas?.drawRect(start, start, dWidth + start, dHeight + start, huePaint)
        canvas?.drawRect(start, start, dWidth + start, dHeight + start, saturationPaint)
    }

    override fun onDetachedFromWindow() {
        super.onDetachedFromWindow()
    }

    fun calculateEffective(x:Float, y:Float):PointF{
        val start = borderSize + paddingLeft
        val dWidth = width - paddingLeft - paddingRight - 2 * borderSize
        val dHeight = height - paddingTop - paddingBottom - 2 * borderSize
        currentPoint.x = min(max(x, start), dWidth)
        currentPoint.y = min(max(y, start), dHeight)
        return currentPoint
    }

    fun getColor(point:PointF):Int{
        return if (width > 0 && height > 0) {
            val hsv = FloatArray(3)
            hsv[0] = 360 * min(max(point.x, 0F), width.toFloat()) / width
            val y = min(max(point.y, 0F), height.toFloat())
            hsv[1] = min(y, height / 2F) / (height / 2)
            hsv[2] = 1 - max(y - height / 2, 0F) / (height / 2)
            Color.HSVToColor(hsv)
        }else{
            -0
        }
    }

    fun getGrad(point:PointF):FloatArray{
        val hsv = FloatArray(3)
        hsv[0] = 360* min(max(point.x,0F),width.toFloat())/width
        hsv[1] = max(min(point.y,height.toFloat()),0F)/height
        hsv[2] = 1 - max(min(point.y,height.toFloat()),0F)/height
        return hsv
    }

    private fun init(){
        setBackgroundColor(Color.GREEN)
    }
}